using System;
using NUnit.Framework;
using SpecMaker.Core;
using SpecMaker.Core.Dsl;
using SpecMaker.Core.Exceptions;
using SpecMaker.UnitTests.SupportClasses;

namespace SpecMaker.UnitTests
{
    public class BaseRuleExecutor
    {
        protected Spec _goodspec;
        protected RuleExecutor _exector;
        protected RuleResult[] _results;

        #region Setup/Teardown

        [SetUp]
        public virtual void SetUp()
        {
            _goodspec =
                Spec.Describes<BankAccount>().WithContext("When Adding Transactions").WithFollowingRules(
                    It.Should("Notify Customer If Balance is below 0", () =>
                    {
                        /*passes*/
                    })
                    , It.Should("Add To Transaction Pool", () =>
                    {
                        throw new Exception("error");
                    })
                   , It.Should("Add transaction to history", () =>
                   {
                       throw new RuleException("rule assertion not passed");
                   })
                     , It.Should("Should Run new OFAC Check", RuleIs.Pending)

                    );

            _exector = new RuleExecutor();
            _results = _exector.Spec(_goodspec);
        }

        #endregion
        
    }
    [TestFixture]
    public class SpecRuleExecutorWhenExecutingARuleThatPasses : BaseRuleExecutor
    {
        [Test]
        public void should_return_description()
        {
            Assert.AreEqual("Notify Customer If Balance is below 0", _results[0].Description);

        }
        [Test]
        public void should_return_status_passed_when_no_exception_occurs()
        {
           
            Assert.AreEqual(RuleStatus.Passed, _results[0].Status);
        }
    }

    [TestFixture]
    public class SpecRuleExecutorWhenExecutingARuleThatFailsAssertion: BaseRuleExecutor
    {


        [Test]
        public void should_return_description()
        {
            Assert.AreEqual("Add transaction to history", _results[2].Description);
        }

        [Test]
        public void should_return_status_Failed()
        {

            Assert.AreEqual(RuleStatus.Failed, _results[2].Status);
        }

    }
    [TestFixture]
    public class SpecRuleExecutorWhenExecutingARuleThatHasUnhandledException : BaseRuleExecutor
    {


        [Test]
        public void should_return_description()
        {
            Assert.AreEqual("Add To Transaction Pool", _results[1].Description);
        }

        [Test]
        public void should_return_status_Error()
        {

            Assert.AreEqual(RuleStatus.Error, _results[1].Status);
        }

        [Test]
        public void should_return_exception_message()
        {

            StringAssert.Contains("error", _results[1].ErrorMessage);
        }

        [Test]
        public void should_return_exception_stack_trace()
        {

            StringAssert.Contains("at SpecMaker.UnitTests.BaseRuleExecutor", _results[1].ErrorMessage);
        }
    }
    [TestFixture]
    public class SpecRuleExecutorWhenExecutingARuleThatHasPendingException : BaseRuleExecutor
    {
        [Test]
        public void should_return_description()
        {
            Assert.AreEqual("Should Run new OFAC Check", _results[3].Description);
        }

        [Test]
        public void should_return_status_Error()
        {

            Assert.AreEqual(RuleStatus.Pending, _results[3].Status);
        }
    }
}